import axios from "axios";
import router from "@/router";
import type {
  AxiosInstance,
  AxiosRequestConfig,
  AxiosResponse,
  InternalAxiosRequestConfig,
} from "axios";

interface HInterceptor {
  //请求成功
  requestSuccessFn?: (
    config: InternalAxiosRequestConfig
  ) => InternalAxiosRequestConfig;
  //请求失败
  requestCatchFn?: (err: any) => any;
  //响应成功
  reponseSuccessFn?: (res: AxiosResponse) => AxiosResponse;
  //响应失败
  responseCatchFn?: (err: any) => any;
}

//引入loading组件
import { ElLoading, ElMessage } from "element-plus";

//loading样式
import "element-plus/es/components/loading/style/css";
//message样式
import "element-plus/es/components/message/style/css";

//loading类型
import type { LoadingInstance } from "element-plus/es/components/loading/src/loading";

//扩展config，灵活定制
interface HRequestConfig extends AxiosRequestConfig {
  //添加一个自定义拦截器
  interceptors?: HInterceptor;
}

//基于class类Axios封装
class HRequest {
  //axios实例成员
  instance: AxiosInstance;
  //loading实例成员
  loading?: LoadingInstance;
  //拦截器配置成员
  interceptor?: HInterceptor;
  constructor(config: HRequestConfig) {
    //创建axios实例并赋值
    this.instance = axios.create(config);

    //单个实例请求拦截器
    this.instance.interceptors.request.use(
      //成功请求
      this.interceptor?.requestSuccessFn,
      //失败请求
      this.interceptor?.requestCatchFn
    );
    //单个实例响应拦截器
    this.instance.interceptors.response.use(
      //响应成功
      this.interceptor?.reponseSuccessFn,
      //响应失败
      this.interceptor?.responseCatchFn
    );

    // 全局请求拦截器
    this.instance.interceptors.request.use(
      (config: InternalAxiosRequestConfig) => {
        //配置loading
        this.loading = ElLoading.service({
          fullscreen: true,
          lock: true,
          text: "正在请求数据...",
          background: "rgba(0, 0, 0, 0.3)",
        });
        //配置token，除了login接口之外，其他接口需要配置token

        if (config.url !== "/login") {
          const token = localStorage.getItem("token");
          //配置请求头token
          token && (config.headers["Authorization"] = token);
        }
        return config;
      },
      (err) => {
        return Promise.reject(err);
      }
    );
    // 全局响应拦截器
    this.instance.interceptors.response.use(
      (res: AxiosResponse) => {
        //关闭loading
        this.loading?.close();
        //如果是登录接口，保存token

        const { msg, status } = res.data.meta;
        //成功状态码数组
        const whiteList = [200, 201, 204];
        //根据状态码判断是否成功返回
        if (whiteList.includes(status)) {
          //成功提示
          ElMessage({
            message: msg,
            type: "success",
            duration: 1500,
          });
          if (res.config.url === "/login") {
            //保存token
            localStorage.setItem("token", res.data.data.token);
            //跳转到home页面
            router.push("/home");
          }

          return res.data;
        }
        //失败提示
        ElMessage({
          message: msg,
          type: "error",
          duration: 1500,
        });

        if (msg === "无效token") {
          //清除token
          localStorage.removeItem("token");
          // 跳转到登录页面
          router.push({ path: "/login" });
        }

        return Promise.reject(msg);
      },
      (err) => {
        return Promise.reject(err);
      }
    );
  }

  //实际调用接口封装
  request<T>(config: HRequestConfig): Promise<T> {
    return new Promise((resolve, reject) => {
      this.instance
        .request<any, T>(config)
        .then((res) => {
          resolve(res);
        })
        .catch((err) => {
          return Promise.reject(err);
        });
    });
  }

  get<T>(config: HRequestConfig): Promise<T> {
    return this.request({ ...config, method: "GET" });
  }
  post<T>(config: HRequestConfig): Promise<T> {
    return this.request({ ...config, method: "POST" });
  }
  put<T>(config: HRequestConfig): Promise<T> {
    return this.request({ ...config, method: "PUT" });
  }
  delete<T>(config: HRequestConfig): Promise<T> {
    return this.request({ ...config, method: "DELETE" });
  }
}

export { HRequest };
